package org.zhangchao.poi.excel.interceptor;

import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.zhangchao.poi.excel.common.ExcelHeader;
import org.zhangchao.poi.excel.exception.ExcelException;
import org.zhangchao.poi.util.DateConverter;
import org.zhangchao.poi.util.DateUtil;

/**
 * Excel 构建对象拦截器，将解析的excle一行对应生成一个指定对象，并加入到对象集合中
 * 
 * @author zhangchao
 * 
 */
public class ExcelBuildModelHandlerInterceptor implements
		ExcelHandlerInterceptor {

	/** 要解析成的对象类型 */
	private Class<?> clazz;

	/** 表头对应的坐标 */
	private Cell headerStartCell;

	/** 数据对应的坐标 */
	private Cell dataStartCell;
	
	/** 日期转换类 */
	private DateConverter dateConverter;
	
	/** 日期转格式*/
	private String dateConverterPattern = "yyyy-mm-dd";
	
	/** 存储列索引对应的，ExcelHeader对象 */
	private Map<Integer, ExcelHeader> headerMap;

	// public ExcelBuildModelHandlerInterceptor() {
	// super();
	// }

	/**
	 * Excel 构建对象拦截器构造方法
	 * 
	 * @param clazz
	 *            要构建对象的类型
	 * @param headerdStartCell
	 *            表头对应的坐标
	 * @param dataStartCell
	 *            数据对应的坐标
	 */
	public ExcelBuildModelHandlerInterceptor(Class<?> clazz,
			Cell headerdStartCell, Cell dataStartCell) {
		super();
		if (null == clazz) {
			throw new ExcelException("没有设置要封装对象的类型，设置要封装对象的Class类型");
		}
		if (null == headerdStartCell) {
			throw new ExcelException("没有设置表头对应的坐标，设置headerdStartCell");
		}
		if (null == dataStartCell) {
			throw new ExcelException("没有设置数据对应的坐标，设置dataStartCell");
		}
		this.clazz = clazz;
		this.headerStartCell = headerdStartCell;
		this.dataStartCell = dataStartCell;
		init();
	}

	/**
	 * 初始化方法
	 */
	private void init() {
		dateConverter = new DateConverter();
		//注册日期转换
		ConvertUtils.register(dateConverter, Date.class);
	}
	
	//@Override
	@SuppressWarnings("unchecked")
	public void handler(Row row, MakeHandler makeHandler,
			ExcelHandlerInterceptorStack handlerStack) {
		List<?> data = makeHandler.prepareModelData();
		int rowNum = row.getRowNum();
		if (null == headerMap && rowNum == headerStartCell.getRowIndex()) {
			buildHeader(row); // 设置映射关系
		} else if (rowNum >= dataStartCell.getRowIndex()) {
			((List<Object>) data).add(buildModel(row));
		}
		handlerStack.handler(row, makeHandler, handlerStack);
	}

	/**
	 * 构建对象
	 * 
	 * @param row
	 * @return
	 */
	private Object buildModel(Row row) {
		Object obj = null;
		try {
			obj = clazz.newInstance();
			for (Cell cell : row) {
				ExcelHeader excelHeader = headerMap.get(cell.getColumnIndex());
				if(null != excelHeader) {
					Object objValue = getCellValue(cell);
					//如果有注解自定义日期类型转换，则使用自定义日期类型转换
					if(null != excelHeader.getDatePattern() && objValue instanceof String) {
						try {
							objValue = DateUtil.parse((String)objValue, excelHeader.getDatePattern());
						} catch (ParseException e) {
							//e.printStackTrace();
							objValue = null;
						}
					}
					BeanUtils.copyProperty(obj, excelHeader.getFieldName(), objValue);
				}
			}
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		return obj;
	}

	
	/**
	 * 设置Excel列索引和要封装对象字段字段对应关系
	 * 
	 * @param row
	 */
	private void buildHeader(Row row) {
		if (null == headerMap) {
			headerMap = new HashMap<Integer, ExcelHeader>();
		}
		List<ExcelHeader> headers = ExcelHeader.buildHeaderList(clazz);
		for (ExcelHeader eh : headers) {
			String columnTitle = eh.getColumnTitle();
			for (Cell cell : row) {
				if (columnTitle.equals(getCellValue(cell))) {
					headerMap.put(cell.getColumnIndex(), eh);
					break;
				}
			}
		}
	}

	/**
	 * 根据cell类型取值
	 * @param cell
	 * @return
	 */
	private Object getCellValue(Cell cell) {
		Object o = null;
		switch (cell.getCellType()) {
		case Cell.CELL_TYPE_BLANK:
			o = "";
			break;
		case Cell.CELL_TYPE_BOOLEAN:
			o = cell.getBooleanCellValue();
			break;
		case Cell.CELL_TYPE_FORMULA:
			o = cell.getCellFormula();
			break;
		case Cell.CELL_TYPE_NUMERIC:
			o = (int) cell.getNumericCellValue();
			break;
		case Cell.CELL_TYPE_STRING:
			o = cell.getStringCellValue();
			break;
		default:
			o = null;
			break;
		}
		return o;
	}

	public Class<?> getClazz() {
		return clazz;
	}

	public void setClazz(Class<?> clazz) {
		this.clazz = clazz;
	}

	public Cell getHeaderStartCell() {
		return headerStartCell;
	}

	public void setHeaderStartCell(Cell headerStartCell) {
		this.headerStartCell = headerStartCell;
	}

	public Cell getDataStartCell() {
		return dataStartCell;
	}

	public void setDataStartCell(Cell dataStartCell) {
		this.dataStartCell = dataStartCell;
	}

	public String getDateConverterPattern() {
		return dateConverterPattern;
	}
	
	/**
	 * 设置日期转换格式
	 * @param pattern
	 */
	public void setDateConverterPattern(String pattern) {
		dateConverter.setPattern(pattern);
		this.dateConverterPattern = pattern;
	}

}
